1 Objective

Perform basic data checks on Rwanda round soil health study data to provide real time feedback to Nathaniel and enumeration teams to maximize the value of the teams in the field.

3 Data

3.1 Baseline and round 1

load("../rw_round_1/fieldDat_final.Rdata")

3.2 Round 2 data

Load data and make variable names nice. ytwo is the complete data. yt is the data I’ll be manipulating.

dataDir <- normalizePath(file.path("..", "..", "data"))
source("../oaflib/commcareExport.R")
source("../oaflib/misc.R")
#source("../oaflib/ccSluthing.R")
ytwo <- getFormData("oafrwanda", "M&E", "17B Ubutaka (Soil)", forceUpdate=T)
[1] "querying commcare-export for 98d142ec1149d0098f4e72ce0a3570600ba53dd4"
[1] "commcare-export --project oafrwanda --query /var/folders/pw/0l8d_x690m7b71_dmx2ww6fw0000gn/T//RtmptioVNX/file212077c729a1.json --output-format csv --output /var/folders/pw/0l8d_x690m7b71_dmx2ww6fw0000gn/T//RtmptioVNX/file2120347e4676.zip --username robert.on@oneacrefund.org --password 0n3@cr3"
[1] "finished querying commcare-export for 98d142ec1149d0098f4e72ce0a3570600ba53dd4"
names(ytwo) <- tolower(make.names(names(ytwo)))
yt <- ytwo %>%
  setNames(gsub("x.form.", "", names(.))) %>%
  mutate(sample_id = tolower(sample_id))
package ‘bindrcpp’ was built under R version 3.3.2

4 Observation count

4.1 Missing data

Reality check some observations. Are they completely missing?

blankRow <- apply(yt, 1, function(x){
  sum(x=="" | is.na(x))
})
naRow <- data.frame(table(round(blankRow/dim(yt)[2],2)*100)) %>%
  mutate(Var1 = as.numeric(as.character(Var1))) %>%
  filter(Var1>=25) %>%
  mutate(Var1 = paste0(Var1, "%"))
kable(naRow, col.names = c("% of columns missing values", "Freq"),format="markdown")

% of columns missing values Freq
25% 125
26% 62
27% 168
28% 35
29% 46
30% 51
31% 39
32% 23
33% 26
34% 25
35% 30
36% 12
37% 8
38% 1
39% 2
42% 29
43% 28
44% 1
45% 2
74% 5
75% 11
76% 24
77% 9
78% 13
79% 1
80% 3

# identify which rows have the most missing values
mostMissing <- ifelse(blankRow > 80, TRUE, FALSE)
missingTab <- yt %>%
  filter(mostMissing==T) %>%
  dplyr::select(district, enumerator_in_16b, village, sample_id, name)
kable(missingTab, format='markdown', caption="Obs with over 80 missing values")
district enumerator_in_16b village sample_id name
Gatsibo_Nlwh nshimiyerugira Icyerekezo 2632 Bajeneza JD'Amaur
Rwamagana Niyigena Jean Pierre Nyarugenge 2875c Benimana Domithira
Rwamagana Utamuriza Jeanne Nyirabujari 2938 11Kayiranga Jean Bosco
Karongi NA Gihumo 1380 Mudakikwa Elias
Karongi yankurije ange Ngoma 1338c Mukarwego Jakerine
Kayonza Hagenimana bienvenue Kibimba 3092c Munyankusi Enoki
Kayonza Hagenimana bienvenue Nyobugogo 3098c Nyirahabimana Florance
Kayonza Hagenimana bienvenue Bwatamama 3101 Sindayigaya Emmanuel
Rwamagana Utamuruza Jeanne Murehe 3009 Niyitegeka Venersnda
Rwamagana Utamuriza Jeanne Gatare 2952 Barahira Eric
Rwamagana Utamuriza Jeanne Gatare 2944 Uwimana Alphonsine
Kayonza NA Bara 2850 Gatsinzi Faustin
Kayonza Dusenge Pierre Kagumiro 2819 Mukandamage Dancile
Kayonza hagenimana bienvenue Kajevuba 2841c Mukabatabazi Donatienne
Rutsiro Habimana Eugene Rugote 2029c Kanakuze Sara
Nyaruguru Nyiramana cloudine Rubuga 602c Bivugire Andre
Nyaruguru Nyiramana cloudine Rubuga 602c Bivugire Andre
Mugonero NA Rugeyo 1767 Bazigama Jean
Nyamasheke NA Mutiti 971c Uzabakiriho Phiripe
Rwamagana Niyigena Jean Pierre Nyarugenge 2874 Mukankunsi Foromina
Karongi Antoinette Uwizeye Gashari 1212 Sindikubwabo Thomas
Mugonero NA Uwingabo 1659 Basabose Pascal
Nyamasheke NA Rugabano 1030 Nyabuyenga Jean
Nyamasheke Hakuzimana Simeon Bururi 793c Kamuzima Pascasie
Gatsibo_Nlwh NA Rwimbogo 2685c Ndikubwimana Ildaphonse
Gatsibo_Lwh Niyidufasha nathanael Rurana 2540 Kwizera Isaac
Nyamasheke Constance Nyiranjamahoro Bigabiro 835c Nubwende Ezira
Nyamasheke Tuyisrnge Emmanuel Misirimbo 866c Urayeneza Purusikiya
Gatsibo_Nlwh Nyandwi Anathalie Kagugu 2663c Nyirampakaniye Eurerie
Kayonza NA Kajevuba 2835c Nyiramuhanda Clementine
Gatsibo_Nlwh Nyandwi Anathalie Gakunyu 2703c Nyirabanguka Francoise
Gatsibo_Nlwh Nyandwi Anathalie Mataba 2711 Nizeyimana Anasthase
Gatsibo_Nlwh Nyandwi Anathalie Bidudu 2709 Kantarama Xaverine
Rutsiro sylvere hategekimana Cyato 2073c Mukamuganga Eugenie
Kayonza Hagenimana bienvenue Nyabugogo 2778c Kankuyo Sesile
Gatsibo_Nlwh nshimiyerugira Gakiri 2610 Bigirimana Jeapolo
Gatsibo_Nlwh Nshimiyerugira Akagarama 1 2732c Nshimiye
Gatsibo_Nlwh NA Burembo 2604c Gatsinzi Alphonse
Gatsibo_Nlwh NA Mwanama 2606 Ntambara Enock
Nyamasheke NA Rambura 1182c Bazimaziki Nehemie
Karongi NA Kirehe 1365c Niyomugabo Tierry
Nyanza ndakaza philbert Buhaza 319 Zirakurwa Uziyeri
Karongi Niyonsaba MJudith Kagangare 1524 Ayindimwe Alexie
Karongi NA Kigarama 1525c Nikuze Elizabeti
Huye NA Kigarama 145 Buregeya Cassien
Rutsiro NA Maryazo 2405c Nyambuga Stephania
Huye NiyonsabaMJudith Rubona 65c Nyirantezimana Oliver
Huye RURANGIRWA Emmanuel Rusuma 130 Buriminyundo Andrea
Karongi Nshimiyimana Clement Ruhande 1423c Murengerankwari Sameul
Karongi Nshimiyimana Clement Nyabivumu 1621c Uwimana Gatarina
Karongi Nshimiyimana Clement Ryangondo 1473 Nyiransabimana Esipelense
Karongi Nshimiyimana Clement NA 1476c Nshimyukiza Emanuel
Karongi NA Muhondo 1266 Nyiranduhura Sarayi
Karongi NA Kivumu 1269c Uwitonze Emmanuel
Rutsiro Venerande N Habimana Musongati 2373c Bucyeyeneza Louis
Rutsiro nyanzira valentine Buruseri 2322c Mbatejurundiagnes
Rutsiro NA Gitete 2321 Musabyimana Christine
Karongi NA Nyamagana 1293 Nyirabanama Monigue
Karongi NA Kigabiro 1298 Munyandamutsa Daniel
Karongi NA Gitega 1397 Nyirangarukiye Eugenie
Karongi Kanyabugoyi Felicien Kavumu 1390 Ngarukiye Simiyoni
Huye NA Kamwambi 14c Ndimbati John
Nyaruguru NA Kubitiro 573c Umbereyifura Renata
Karongi NA NA 1298c Mukabera Beatrice
Karongi NA NA 1295 Tubisabimana Innocent
Karongi NA NA 1295c Uwamariya Donatha

Some observations have 80% of observations missing. What’s going on with these? I’m only showing rows with greater than 25% missing. It’s somewhat arbitrary but to not have data for a fourth of the survey seems odd.

4.2 Matches with previous rounds

#table(yt$sample_id %in% unique(fieldDat$sample_id))

Through September 25, 2017 we have one soil sample id in round 2 that doesn’t exist in previous rounds. It is sample_id 1437, 1300, 14c, 1298c, 1295, 1295c.

What is up with that observation?

4.3 Completion rates

baseComplete <- fieldDat %>%
  filter(season =="15b") %>%
  dplyr::select(sample_id) 
compB <- round(prop.table(table(baseComplete$sample_id %in% yt$sample_id)),2)
r1Complete <- fieldDat %>%
  filter(season =="16b") %>%
  dplyr::select(sample_id) 
compR1 <- round(prop.table(table(r1Complete$sample_id %in% yt$sample_id)),2)

Through September 25, 2017 we’ve found 100% of baseline farmers. We have 10 to go.

Through September 25, 2017 we’ve found 100% of round 1 farmers. We have 11 to go.

As we get closer to the end of enumeration I will produce a report of sample_ids that have not yet been surveyed so we can understand precisely why some farmers were not found again.

4.4 Attrition summary

# code to check merge match before match is performed
# the code should show you how many overlaps you have in your merge variable
# and a summary of the values that don't match
# tested using ke_round_1_py
vecFiller <- function(vec){
  vec[2] = ifelse(is.na(vec[2]), 0, vec[2])
  return(vec)
}
mergeReport <- function(master, using){
  
  # dat1 into dat2
  
  c1 <- vecFiller(table(master %in% using))
  c2 <- vecFiller(table(using %in% master))
  
  notMatch1 <- master[!master %in% using]
  notMatch2 <- using[!using %in% master]
  
  tab <- data.frame(rbind(c1, c2))
  rownames(tab) <- c("Master in Using", "Using in Master")
  
  outList <- list(tab, notMatch1, notMatch2)
  names(outList) <- c("matching.table", "missing.from.using", "missing.from.master")
  
  return(
    outList
  )
  
  
}
attReport <- mergeReport(baseComplete$sample_id, yt$sample_id)

We currently have 10 more surveys to complete from the baseline. The complete list of missing farmer ids will be shared once we’re down to a more reasonable number.

4.4.1 Attrition farmer list

attOut is the list of baseline farmers not found during the second survey round. attReport are those farmers that are missing

attOut <- fieldDat %>%
  filter(season =="15b") %>%
  filter(sample_id %in% attReport$missing.from.using) %>%
  dplyr::select(sample_id, district, village)
#load the baseline data
load("../rw_round_1/rawBaselineWithIdentifers.Rdata")
attritionTab <- d %>% 
  dplyr::select(district, selected_cell, umudugudu,  sample_id, farmer_name) %>%
  mutate(sample_id = tolower(sample_id), # because we're makring those not found
         found = ifelse(sample_id %in% attOut$sample_id, FALSE, TRUE)) %>%
  left_join(., ytwo[, c("x18a.farmer.name", "x18b.name.of.the.respondent", "x19a.farmer.phone.number", "x.form.sample_id",
                        "x20.in.case.we.can.not.reach.the.client.directly..please.provide.a.neighbor.s.phone.number",
                        "x14a.were..you.a.tubura.client.17a.", "x14b.are.you.a.tubura.client.17b.","x14c.are.you.a.tubura.client.in.18a.")], by=c("sample_id"= "x.form.sample_id"))
attritionTab <- attritionTab[,c(4,1,2,3,5,6, 7:13)]
#length(attritionTab$sample_id)==length(unique(attritionTab$sample_id))
# load data from Eric J on 9/11 - combine my missingn with those without a sample and update the googlesheet
ejDat1 <- read_xlsx("attrition table2017 09 11_EJ.xlsx", sheet=1) %>% 
  dplyr::select(sample_id, `sample collected (from tracker)?`, `reason (from tracker)`) %>%
  rename(sample_collected = `sample collected (from tracker)?`,
         reason = `reason (from tracker)`)
ejDat2 <- read_xlsx("attrition table2017 09 11_EJ.xlsx", sheet=2) %>% 
  dplyr::select(sample_id, `sample collected?`, reason) %>%
  rename(sample_collected = `sample collected?`) %>%
  rbind(., ejDat1)
#length(ejDat2$sample_id)==length(unique(ejDat$sample_id)) # duplicates in the missing data
# report missing values in the duplicates
dups <- ejDat2[duplicated(ejDat2$sample_id), "sample_id"] %>% 
  filter(!is.na(sample_id))
# show all the farmers for which we have multiple reasons listed:
# ejDat2 %>%
#   filter(ejDat2$sample_id %in% dups$sample_id) %>%
#   arrange(sample_id) %>%
#   kable(., format='markdown')

Eric, there isn’t clarity in Jeannette’s form about what has and has not been collected. Can she make a master database instead of two separate ones? Add a second column if you want to indicate the issue. For the time being I’m not going to add this into the rwR2Attrition google sheet until we have a definitive answer on what the status is.

# now put this information with the attrition Tab
#attritionTab <- left_join(attritionTab, ejDat2, by="sample_id")
  
write.csv(attritionTab, file=paste0("attritionTabs/attrition table", format(Sys.time(), '%Y %m %d'), ".csv"), row.names=F)
# also update a googlesheet to make collaborating on this possible:
library(googlesheets)
package ‘googlesheets’ was built under R version 3.3.2
# first uploading of the data
# test <- gs_upload(file=paste0("attritionTabs/attrition table", format(Sys.time(), '%Y %m %d'), ".csv"), "rwR2Attrition", overwrite=T)
# now I want to only edit certain rows:
# test <- test %>% 
#   gs_edit_cells(input = attritionTab$found,
#                 anchor = "F2", byrow=FALSE)
# 
# # bring in info from M&E team, merge reasons with current table and only show the farmers for which we are still missing an explanation
# 
# test <- read_xlsx("Farmer not find for SHS survey 7.9.2017.xlsx", sheet=2) %>%
#   rename(sample_id = `Soil ID`) %>%
#   mutate(sample_id = tolower(sample_id))
# table(test$sample_id %in% attritionTab$sample_id) # do they appear among the missing?
# table(test$sample_id %in% subset(fieldDat, fieldDat$season=="15b")$sample_id) # they are farmers but I've found them
  # dplyr::select(`Reason not found`, `Reason not found other`, District, Cell, Village, `Cell field`, `Respondent name`, `Farmer tel`, `Respondent tel`, `Neighbor tel`, sample_id) %>%
  # left_join(., attritionTab, by="sample_id") %>%
  # as.data.frame()
# find the farmer name in the original baseline data?
datatable(attritionTab)

5 Data reality check

The variable names are not great. I think it’s due to the CommCare API export. I’m going to see if there’s an easier way to have uesable variable names. I’ve creaetd a CC export titled “M&E - Soil Health Study - 17B Ubutaka (Soil)” on August 8th. I’m only using it to get more usable variable names quickly. Ideally there’d be away to get that info directly from CommCare.

varNames <- read_csv("M&E - Soil Health Study - 17B Ubutaka (Soil) (2017-08-04) 2017-08-04.csv") %>% 
  setNames(gsub("form.", "", names(.))) %>%
  setNames(gsub("farmer.", "", names(.))) %>%
  setNames(gsub("prim_17a_.", "", names(.))) %>%
  setNames(gsub("sec_17a_.", "", names(.))) %>%
  setNames(gsub("prim_17b_.", "", names(.))) %>%
  setNames(gsub("sec_17b_.", "", names(.))) %>%
  setNames(gsub("ammend_17a_.", "", names(.))) %>%
  setNames(gsub("ammend_17b_.", "", names(.))) %>% 
  as.data.frame()
Parsed with column specification:
cols(
  .default = col_character(),
  number = col_integer(),
  form.farmer_found = col_integer(),
  completed_time = col_datetime(format = ""),
  started_time = col_datetime(format = ""),
  received_on = col_datetime(format = "")
)
See spec(...) for full column specifications.
names(yt)[11:112] <- names(varNames)[3:104]
# rename one variable to remove duplicates
names(yt)[31] <- "nameOne"
names(yt) <- tolower(names(yt))
# manually fix a couple other names
names(yt)[53] <- "crop1_yield_comparison_17a"
names(yt)[58] <- "crop2_yield_comparison_17a"

5.1 Categorical variables

catVars <- names(yt)[sapply(yt, function(x){
  is.character(x)
})]
enumClean <- function(dat, x, toRemove){
  dat[,x] <- ifelse(dat[,x] %in% toRemove, NA, dat[,x])
  return(dat[,x])
}
strTable <- function(dat, x){
  varName = x
  tab = as.data.frame(table(dat[,x], useNA = 'ifany'))
  tab = tab[order(tab$Freq, decreasing = T),]
  end = ifelse(length(tab$Var1)<10, length(tab$Var1), 10)
  repOrder = paste(tab$Var1[1:end], collapse=", ")
  out = data.frame(variable = varName,
                   responses = repOrder)
  
  return(out)
}
# clean up known values
catEnumVals <- c("-99", "-88", "- 99", "-99.0", "88", "_88", "- 88", "0.88",
                 "--88", "__88", "-88.0", "99.0")
yt[,catVars] <- sapply(catVars, function(y){
  yt[,y] <- enumClean(yt,y, catEnumVals)
})
# put all categorical values in lower
yt[,catVars] <- sapply(yt[,catVars], function(x) tolower(x))
responseTable <- do.call(rbind, lapply(catVars, function(x){
  strTable(yt, x)
}))

5.1.1 Table of categorical responses

kable(responseTable, format="markdown")
variable responses
appformid ../../data/commcare_cache/98d142ec1149d0098f4e72ce0a35706
id 00013332-860c-4b9f-b513-e6777d7a7469, 00072a70-bd5f-4291-a81d-17840b4884b5, 000ea6f0-2fb7-45ed-b0b0-4bff8d6096c5, 00162ffc-1c98-485a-be46-f8783e80647b, 00b3e2f5-c53e-4ff5-90f8-db734cd1b662, 00d89c38-ac7d-4b75-9d9b-947844f0a8a8, 00f7ff4c-84cb-43cb-aacc-d5392278e936, 0103734f-0b30-4bee-a6ca-172f98772cce, 01270485-942e-47c7-9d23-5233f1cd0f52, 014ef092-98a2-4ecb-9194-ba04e3255bd2
domain oafrwanda
date_header NA
metadata.deviceid 358310068624197, 358310068699280, 357103076500702, 357103076505578, 358310068599233, 358310068599506, 358310068599761, 358310068699157, 357103076496752, 358310068263228
metadata.userid 0cb6454736db554904dbdd8a32fd2572, 7954ad9145fd68242150fb3a7d001dec, 0cb6454736db554904dbdd8a32fd17b4, 0cb6454736db554904dbdd8a32fb90ec, 0cb6454736db554904dbdd8a32fe521f, 0cb6454736db554904dbdd8a32fe3e2f, 0cb6454736db554904dbdd8a32fe498a, 0cb6454736db554904dbdd8a32fe5083, 408e98c5bd832100d1e530d66a659f2c, 408e98c5bd832100d1e530d66ac43fea
metadata.username nym2, gat1, nym3, rut6, rwm1, kyz1, kyz2, rwm2, rwm3, rwm4
form.case..case_id 4968796dfe4e4f8990794c0373faa06e, 4aed5f40760f41b4b798a265c16db675, 62a5ef2a6aae4ac4919bdf5d78d94709, 98922c8fae5e43c58c6502e6ff6f33df, aa8fe94224cf443fb9281d674ee913fa, ccf9cb15dad44273b89dc8b979a2c878, f704b47c73a14135a16298c68ed4d74c, 00562917ad364da18ac1f673415ed116, 0073c4c117924c0fae4f231b0482f78c, 00c9941f634546b5be6dccd93bbf6d4f
start_time 12:00:00.000+02, 11:30:00.000+02, 10:30:00.000+02, 10:00:00.000+02, 09:00:00.000+02, 08:30:00.000+02, 13:06:00.000+02, 08:18:00.000+02, 09:20:00.000+02, 10:06:00.000+02
enumerator ntabudakeba olive, niyidufasha nathanael, hagenimana bienvenue, murekatete alphonsine, niyigena jean pierre, nyirampano bernadette, zimukwiye dominique, utamuriza jeanne, nyanzira valentine, habimana eugene
not_find_why NA, other, moved, deceased, notfarm
not_find_why_other NA, ntakiwuhinga, umurima we wafashwe na leta kubera umuhanda, bahahaye undi muvandi we, bahatanze i minani uwahahingaga ntiyo ngera kuhahinga uwobahahaye naramubuze, bahateye ishyamba, baragabanye nk umuryango niyongera kuhahinga, iyi fishe yari yakozwe ari igeregeza kunshuro yambere 2015b iba synclonise bitari ngombwa niyo mpamvu kuri ino nshuro nta makuru yayo agaragara, mubirigi eliel yarawugurishije uwuhinga ni racher ahogeze, ntakihahinga barahamwatse
soil_id NA, 1646, 1676, 2230c, 2333c, 2885, 978c, 10, 1001, 1001c
soil_id2_ NA, 1646, 1676, 2230c, 2333c, 2885, 978c, 10, 1001, 1001c
text_final.photo NA, 1501036672690.jpg, 1501040329114.jpg, 1501052471877.jpg, 1501052777690.jpg, 1501053428782.jpg, 1501053613964.jpg, 1501053734690.jpg, 1501053901444.jpg, 1501053976830.jpg
district_17b karongi, rutsiro, huye, rwamagana, nyamasheke, gatsibo, nym, nyamagabe, kayonza, gisagara
cell_input_17b NA, kabona, rubumba, kagarama ka, muhororo, marimba a, butiruka, kibyagira a, mubuga, mutongoca
cell_field_17b NA, rubumba, mubuga, kagarama, nyabicwamba, kabona, gisoke, kibyagira, nyagatare, birambo
village_17b NA, kabeza, kigarama, murambi, karambo, kabuga, rugarama, kivumu, gasharu, gatare
nameone NA, habimana emmanuel, hakizimana fidele, hakizimana joel, hategekimana francois, havugimana celestin, karekezi celestin, mujawamariya beatrice, mukeshimana claudine, nkundimana j baptiste
name_respondent NA, habimana emmanuel, habimana celestin, karekezi celestin, kayumba josephine, mujawamariya beatrice, mukangiriye donatha, mukankusi beatrice, munyensanga emmanuel, musabyimana beatrice
tel NA, 0, _99, 99, ntayo, --99, -9, 07, 0722007421, 0722014089
tel_respondent NA, 0, _99, 99, ntayo, --99, -9, 0727005638, 0727121920, 078
neighbor_tel NA, -8, 0, 0787393574, _99, 0722475878, 0727911362, 0781143339, 0782897631, 0782936691
gender male, female, NA
respondent_gender female, male, NA
crop1_17a gor, shy, big, not_plant_17a, yum, jum, soya, NA, ray, insina
seed_maize_crop1_17a NA, new_hybrid, gor_nsp, opv_saved, hybride_saved, opv_new
crop2_17a no_other_plant_17a, yum, gor, NA, insina, big, jum, ray, shaz, soya
seed_maize_crop2_17b NA, gor_nsp, opv_saved, hybride, hybride_saved, opv_new
fert1_17a none, dap, NA, npk-17, urea, npk-22, npk2555
fert2_17a none, urea, NA, dap, npk-17
compost_qual_17a good, average, NA, bad
compost_type_17a cow, NA, goat, pig, kitchen_waste, plant, other, human, chicken
compost_other_17a NA, intama, iy'inka n'ihene, compost, composite, inka n'ihene, composte, ibyatsi bagiye bahira, ibyatsi byinshi yavanzemo amase yinka, ifumbire ya wese
lime_17a no_lime, NA, lime_outside, lime_tubura, both_tubura_non_tubura
crop1_17b big, shy, saka, jum, not_plant_17b, gor, yum, soya, ray, NA
seed_maize_crop1_17b NA, new_hybrid, opv_new, gor_nsp, opv_saved, hybride_saved
crop2_17b not_plant_crop2_17b, yum, NA, gor, insina, jum, big, not_plant_crop217b, soya, shaz
fert1_17b none, dap, NA, npk-17, urea, npk-22, npk2555
fert2_17b NA, none, urea, dap, npk-17, npk-22, npk2555
compost_qual_17b NA, average, good, bad
compost_type_17b NA, cow, goat, pig, kitchen_waste, plant, other, human, chicken
compost_other_17b NA
lime_17b no_lime, NA, lime_outside, lime_tubura, both_tubura_non_tubura
crop_residues feed_animals, mulching, leave_field, compost_use, NA, burn_field, other, sell, burn_discard
anti_erosion_efforts drainageditch, nothing, radicalterrace, gradualterrace, NA
d_plant_rows_slope_17b na, across_slope, NA, down_slope
other_comments ntazo, ntakibazo, ntayo, NA, 0, no comment, ntacyahindutse, ntacyahindutse., ntazo., noncomments
finish_time 10:30:00.000+02, 11:30:00.000+02, 08:30:00.000+02, 10:40:00.000+02, 09:45:00.000+02, 10:50:00.000+02, 13:27:00.000+02, 13:50:00.000+02, 15:00:00.000+02, 08:50:00.000+02
description NA, igiti, ku musozi, iruhande rw'inzira, haruguru y'inzira, hejuru yinzira, insina, munsi y,inzira, ukikijwe nurubingo, intangiro hari inzira
neighbor_or_voisin_phone NA
district rutsiro, karongi, nyamasheke, mugonero, huye, rwamagana, gatsibo_nlwh, gatsibo_lwh, kayonza, nyamagabe
enumerator_in_16b NA, hagenimana bienvenue, mucyowimihigo j mv, nyandwi anathalie, utamuriza jeanne, zimukwiye dominique, niyidufasha nathanael, nyirangirimana jeanne, torero pacifique, nshimiyerugira
cell rubumba, kabona, muhororo, nyabicwamba a, gitara b, kibyagira a, cyarubare a, gatsibo a, gitara a, gitara c
respondent_in_16b NA, habimana emmanuel, akimana jeannette, benimana domithira, bimenyande djumapri, hagumagatsi gaspard, karekezi celestin, kayiranga j bosco, mujawamariya beatrice, mukabinyange cecile
village kigarama, kabeza, murambi, kabuga, gasharu, karambo, rugarama, kivumu, gatare, remera
sample_id 1264, 2632, 2875c, 2938, 315, 60, 602c, 10, 1001, 1001c
client_in_15b yego, oya, NA
client_in_16b_or_17a NA
gps_hidden NA, -2.1754531 29.2847899 0.0 4138.0, -2.1774711 29.2884729 0.0 4970.0, -2.0294828 30.6384099 0.0 2815.0, -2.0564286 29.3996455 0.0 52.4, -1.593719 30.2564566 0.0 3647.0, -1.8408223 29.3231408 0.0 4321.0, -2.0392077 30.6286476 0.0 5000.0, -2.1717515 30.5800986 0.0 3840.0, -2.4216136 29.2036459 0.0 4227.0
farmer_phone ., 782924160, 722063424, 722354432, 782475072, 782901568, 782925056, 782929152, 782936320, 782936704
enumerator_in_15b mucyowimihigo j mv, rukundo japhet, dusenge pierre, hagenimana bienvenue, nshimiyerugira, nyirangirimana jeanne, torero pacifique, niyidufasha nathanael, zimukwiye dominique, niyonsenga joel
respondent_phone ., 722063424, 723013760, 726201472, 727511488, 728496832, 782708544, 782906112, 782929280, 782929344
name habimana emmanuel, 11kayiranga jean bosco, bajeneza jd'amaur, benimana domithira, bivugire andre, bugabo jean, hakizimana fidele, hategekimana francois, havugimana celestin, iyamurenye amoni

5.1.2 Categorical var graphs

  • district_17b names are spelled wrong. How is that possible? Do we care?
repGraphs <- function(dat, x){
  tab = as.data.frame(table(dat[,x], useNA = 'ifany'))
  tab = tab[order(tab$Freq, decreasing = T),]
  print(
    ggplot(data=tab, aes(x=Var1, y=Freq)) + geom_bar(stat="identity") +
      theme(legend.position = "bottom", axis.text.x = element_text(angle = 45, hjust = 1)) +
      labs(title =paste0("Composition of variable: ", x))
  )
}
adminVars <- tolower(c(names(yt)[grep("meta", names(yt))],"enum_name", "text_final.photo",  "participation", "refusal", "phone",  "comment", "gps", "sample_id", "sampling.barcode", "id", "domain", "date_header", "form.case..case_id", "site", "district1", "site1", "plot.location", "New_soil_sample_id", "#form/Sampling2017_Complete", "appformid",names(yt)[grep("soil_id", names(yt))], "nameOne", "tel", "tel_respondent", "neighbor_tel", "finish_time", "other_comments", "Description", "neighbor_or_voisin_phone", "name", "cell_field_17b", "name_respondent","respondent_in_16b","gps_hidden", "farmer_phone", "respondent_phone", "village", "cell", names(yt)[grep("enumerator", names(yt))], "start_time", "village_17b", "cell_input_17b", "not_find_why_other", "compost_other_17a"))
nonAdminVars <- catVars[!catVars %in% adminVars]
for(i in 1:length(nonAdminVars)){
  repGraphs(yt, nonAdminVars[i])
}

5.2 Numeric variables

numVars <- names(yt)[sapply(yt, function(x){
  is.numeric(x)
})]

Basic cleaning of known issues like enumerator codes for DK, NWR, etc.

enumVals <- c(-88,-85, -99, -9)
yt[,numVars] <- sapply(numVars, function(y){
  yt[,y] <- enumClean(yt,y, enumVals)
  yt[,y] <- as.numeric(yt[,y])
})
NAs introduced by coercion

5.2.1 Numeric var graphs

temp <- numVars
noNeed <- c("intro.intro", "text_final.d_photo", "text_final.d_soilsample")
numVars <- numVars[!numVars %in% noNeed]
# remove variables that are entirely missing
totallyMissing <- sapply(yt[,numVars], function(x){
  all(is.na(x))
  })
numVars <- numVars[totallyMissing==F]
for(i in 1:length(numVars)){
    if(length(unique(yt[,numVars[i]]))>10){
      print(ggplot(data=yt, aes(x=yt[,numVars[i]])) +  
              geom_density() + 
              theme(legend.position = "bottom", axis.text.x = element_text(angle = 45, hjust = 1)) + 
              labs(x = numVars[i])
            )
    } else{
    print(ggplot(data=yt, aes(x=yt[,numVars[i]])) + 
            geom_histogram(stat="count") + 
            theme(legend.position = "bottom", axis.text.x = element_text(angle = 45, hjust = 1)) +
            labs(x = numVars[i])
      )
    }
    #multiplot(temp1, temp2, cols = 2
}
Ignoring unknown parameters: binwidth, bins, pad

6 Follow up

detectOutlier <- function(dat, x){
# function checks distribution and if lognormal, coverts and outputs
# outliers from log normal distribution. have to remove 0s to check
  fits <- list(
 no = fitdistr(dat[,x][complete.cases(dat[,x])],"normal"),
 lo = fitdistr((dat[,x])[complete.cases(dat[,x]) & dat[,x]!=0 & dat[,x]>0],"log-normal")
 #ca = fitdistr(dat[,x][complete.cases(dat[,x])],"cauchy"),
 #we = fitdistr(dat[,x][complete.cases(dat[,x])], "weibull")
 )
# get the logliks for each model...
fitCheck <- sapply(fits, function(i) i$loglik)
bestFit <-names(which.max(fitCheck))
trans <- sapply(dat[,x], function(y){
  ifelse(bestFit=="lo", log10(y+1), y)
})
  
  
  q1 = summary(trans)[[2]]
  q3 = summary(trans)[[5]] 
  iqr = q3-q1
  mark  = ifelse(trans < (q1 - (1.5*iqr)) | trans > (q3 + (1.5*iqr)), 1,0)
  # tab = rbind(
  #   summary(d[,x]),
  #   summary(d[mark==0, x])
  # )
  out = dat[mark==1, c("district", "cell", "enumerator", "sample_id", "farmer_phone", x)]
  out = melt(out, measure.vars = x)
  out = out[!is.na(out$district),]
  
  return(out)
}
printIQR <- do.call(rbind, lapply(numVars, function(y){
  #print(y)
  return(detectOutlier(yt, y))
}))
NaNs producedNaNs producedNaNs producedNaNs producedNaNs produced
printIQR <- printIQR[order(printIQR$enumerator,printIQR$cell, printIQR$sample_id),]

6.1 Specific points

Compost application and quantity

This appears to be odded coded. Some “I didn’t use compost” are 0s while others are NA.

table(yt$kg_compost_17a, yt$compost_17a, useNA = 'ifany')[c(1:10),]
      
        0  1 <NA>
  0     0  1    0
  5     0  1    0
  6     0  1    0
  10    0  3    0
  12.5  0  1    0
  15    0  9    0
  16    0  1    0
  20    0 19    0
  24    0  2    0
  25    0  8    0
modifyOutlierOutput <- function(dat, varname, vals){
  dat = dplyr::filter(dat, variable!=varname & (!value %in% vals))
  return(dat)
}
printIQR <- modifyOutlierOutput(printIQR, "found", 1)
printIQR <- modifyOutlierOutput(printIQR, "compost", 1)
printIQR <- modifyOutlierOutput(printIQR, "compost_17a", 0)
printIQR <- modifyOutlierOutput(printIQR, "n_chickens", 2:7)

Read the values in this table with the above histograms and density plots in mind. Not all the values listed in the table will be impossible values but they were flagged for being far from the central mass of values we have on that data point

datatable(printIQR)
write.csv(printIQR, file=paste0("output/", "rw_shs_r2 vars to check update",format(Sys.time(), '%B %d %Y'),  ".csv"), row.names = F)
for(i in 1:length(unique(printIQR$enumerator))){
  outSheet <- printIQR[printIQR$enumerator==unique(printIQR$enumerator)[i], ]
  write.csv(outSheet, file=paste("output",
          paste("rw_shs_r2 vars to check ", unique(printIQR$enumerator)[i], ".csv", sep = ""), sep = "/"))
  
}
LS0tCnRpdGxlOiAiUndhbmRhIFNvaWwgSGVhbHRoIFN0dWR5IC0gUm91bmQgMiBDaGVjayIKYXV0aG9yOiAiW01hdHQgTG93ZXNdKG1haWx0bzptYXR0Lmxvd2VzQG9uZWFjcmVmdW5kLm9yZykiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCICVkLCAlWScpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBmaWdfaGVpZ2h0OiA2CiAgICB0aGVtZTogZmxhdGx5CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA2CiAgICB0b2NfZmxvYXQ6IHllcwpzdWJ0aXRsZTogIk9uLWdvaW5nIGRhdGEgY2hlY2siCi0tLQpgYGB7ciBlY2hvPUYsIG1lc3NhZ2U9RkFMU0V9CiMjIyMgc2V0IHVwCiMjIGNsZWFyIGVudmlyb25tZW50IGFuZCBjb25zb2xlCnJtKGxpc3QgPSBscygpKQpjYXQoIlwwMTQiKQoKIyMgc2V0IHVwIHNvbWUgZ2xvYmFsIG9wdGlvbnMKIyBhbHdheXMgc2V0IHN0cmluZ3NBc0ZhY3RvcnMgPSBGIHdoZW4gbG9hZGluZyBkYXRhCm9wdGlvbnMoc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkKCiMgc2hvdyB0aGUgY29kZQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCgojIGRlZmluZSBhbGwga25pdHIgdGFibGVzIHRvIGJlIGh0bWwgZm9ybWF0Cm9wdGlvbnMoa25pdHIudGFibGUuZm9ybWF0ID0gJ2h0bWwnKQoKIyBjaGFuZ2UgY29kZSBjaHVuayBkZWZhdWx0IHRvIG5vdCBzaG93IHdhcm5pbmdzIG9yIG1lc3NhZ2VzCmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkKCiMjIGxvYWQgbGlicmFyaWVzCiMgZHBseXIgYW5kIHRpYmJsZSBhcmUgZm9yIHdvcmtpbmcgd2l0aCB0YWJsZXMKIyByZXNoYXBlIGlzIGZvciBlYXN5IHRhYmxlIHRyYW5zZm9ybWF0aW9uCiMga25pdHIgaXMgdG8gbWFrZSBwcmV0dHkgdGFibGVzIGF0IHRoZSBlbmQKIyBnZ3Bsb3QyIGlzIGZvciBtYWtpbmcgZ3JhcGhzCiMgcmVhZHhsIGlzIGZvciByZWFkaW5nIGluIEV4Y2VsIGZpbGVzCiMgTUFTUyBpcyBmb3IgcnVubmluZyBib3hjb3ggdGVzdHMKIyBncmlkRXh0cmEgaXMgZm9yIGFycmFuZ2luZyBwbG90cwojIGNvd3Bsb3QgaXMgZm9yIGFkZGluZyBzdWJ0aXRsZXMgdG8gcGxvdHMKIyByb2J1c3RiYXNlIGlzIHRvIHJ1biByb2J1c3QgcmVncmVzc2lvbnMgdG8gY29tcGVuc2F0ZSBmb3Igb3V0bGllcnMKIyBjYXIgaXMgZm9yIHBlcmZvcm1pbmcgbG9naXQgdHJhbnNmb3JtYXRpb25zCmxpYnMgPC0gYygiZHBseXIiLCAicmVzaGFwZTIiLCAia25pdHIiLCAiZ2dwbG90MiIsICJ0aWJibGUiLCAicmVhZHhsIiwgCiAgICAiTUFTUyIsICJncmlkRXh0cmEiLCAiY293cGxvdCIsICJyb2J1c3RiYXNlIiwgImNhciIsICJrbml0ciIsICJEVCIsICJyZWFkciIpCmludmlzaWJsZShsYXBwbHkobGlicywgcmVxdWlyZSwgY2hhcmFjdGVyLm9ubHkgPSBULCBxdWlldGx5ID0gVCwgd2Fybi5jb25mbGljdHMgPSBGKSkKCiMjIyMgZGVmaW5lIGhlbHBmdWwgZnVuY3Rpb25zCiMgZGVmaW5lIGZ1bmN0aW9uIHRvIGFkanVzdCB0YWJsZSB3aWR0aHMKaHRtbF90YWJsZV93aWR0aCA8LSBmdW5jdGlvbihrYWJsZV9vdXRwdXQsIHdpZHRoKSB7CiAgd2lkdGhfaHRtbCA8LSBwYXN0ZTAocGFzdGUwKCc8Y29sIHdpZHRoPSInLCB3aWR0aCwgJyI+JyksIGNvbGxhcHNlID0gIlxuIikKICBzdWIoIjx0YWJsZT4iLCBwYXN0ZTAoIjx0YWJsZT5cbiIsIHdpZHRoX2h0bWwpLCBrYWJsZV9vdXRwdXQpCn0KYGBgCgojIE9iamVjdGl2ZQoKUGVyZm9ybSBiYXNpYyBkYXRhIGNoZWNrcyBvbiBSd2FuZGEgcm91bmQgc29pbCBoZWFsdGggc3R1ZHkgZGF0YSB0byBwcm92aWRlIHJlYWwgdGltZSBmZWVkYmFjayB0byBOYXRoYW5pZWwgYW5kIGVudW1lcmF0aW9uIHRlYW1zIHRvIG1heGltaXplIHRoZSB2YWx1ZSBvZiB0aGUgdGVhbXMgaW4gdGhlIGZpZWxkLgoKIyBLZXkgdGFrZWF3YXlzCgo+IFNlZSBbZmFybWVycyByZW1haW5pbmcgdG8gYmUgc3VydmV5ZWRdKCNhdHRyaXRpb24tZmFybWVyLWxpc3QpCgo+IFNlZSBbY2F0ZWdvcmljYWwgZ3JhcGhzXSgjY2F0ZWdvcmljYWwtdmFyLWdyYXBocykKCj4gU2VlIFtudW1lcmljYWwgdmFyaWFibGUgZ3JhcGhzXSgjbnVtZXJpYy12YXItZ3JhcGhzKQoKPiBTZWUgW3ZhcmlhYmxlcyBmb3IgZm9sbG93IHVwXSgjc3BlY2lmaWMtcG9pbnRzKQoKIyBEYXRhCgojIyBCYXNlbGluZSBhbmQgcm91bmQgMQoKYGBge3J9CmxvYWQoIi4uL3J3X3JvdW5kXzEvZmllbGREYXRfZmluYWwuUmRhdGEiKQpgYGAKCiMjIFJvdW5kIDIgZGF0YQpMb2FkIGRhdGEgYW5kIG1ha2UgdmFyaWFibGUgbmFtZXMgbmljZS4gYHl0d29gIGlzIHRoZSBjb21wbGV0ZSBkYXRhLiBgeXRgIGlzIHRoZSBkYXRhIEknbGwgYmUgbWFuaXB1bGF0aW5nLgpgYGB7ciBsb2FkaW5nIGRhdGEsIG1lc3NhZ2U9RkFMU0V9CmRhdGFEaXIgPC0gbm9ybWFsaXplUGF0aChmaWxlLnBhdGgoIi4uIiwgIi4uIiwgImRhdGEiKSkKc291cmNlKCIuLi9vYWZsaWIvY29tbWNhcmVFeHBvcnQuUiIpCnNvdXJjZSgiLi4vb2FmbGliL21pc2MuUiIpCiNzb3VyY2UoIi4uL29hZmxpYi9jY1NsdXRoaW5nLlIiKQoKeXR3byA8LSBnZXRGb3JtRGF0YSgib2FmcndhbmRhIiwgIk0mRSIsICIxN0IgVWJ1dGFrYSAoU29pbCkiLCBmb3JjZVVwZGF0ZT1UKQoKbmFtZXMoeXR3bykgPC0gdG9sb3dlcihtYWtlLm5hbWVzKG5hbWVzKHl0d28pKSkKCnl0IDwtIHl0d28gJT4lCiAgc2V0TmFtZXMoZ3N1YigieC5mb3JtLiIsICIiLCBuYW1lcyguKSkpICU+JQogIG11dGF0ZShzYW1wbGVfaWQgPSB0b2xvd2VyKHNhbXBsZV9pZCkpCmBgYAoKIyBPYnNlcnZhdGlvbiBjb3VudAoKIyMgTWlzc2luZyBkYXRhClJlYWxpdHkgY2hlY2sgc29tZSBvYnNlcnZhdGlvbnMuIEFyZSB0aGV5IGNvbXBsZXRlbHkgbWlzc2luZz8gCmBgYHtyfQpibGFua1JvdyA8LSBhcHBseSh5dCwgMSwgZnVuY3Rpb24oeCl7CiAgc3VtKHg9PSIiIHwgaXMubmEoeCkpCn0pCgpuYVJvdyA8LSBkYXRhLmZyYW1lKHRhYmxlKHJvdW5kKGJsYW5rUm93L2RpbSh5dClbMl0sMikqMTAwKSkgJT4lCiAgbXV0YXRlKFZhcjEgPSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihWYXIxKSkpICU+JQogIGZpbHRlcihWYXIxPj0yNSkgJT4lCiAgbXV0YXRlKFZhcjEgPSBwYXN0ZTAoVmFyMSwgIiUiKSkKa2FibGUobmFSb3csIGNvbC5uYW1lcyA9IGMoIiUgb2YgY29sdW1ucyBtaXNzaW5nIHZhbHVlcyIsICJGcmVxIiksZm9ybWF0PSJtYXJrZG93biIpCgojIGlkZW50aWZ5IHdoaWNoIHJvd3MgaGF2ZSB0aGUgbW9zdCBtaXNzaW5nIHZhbHVlcwptb3N0TWlzc2luZyA8LSBpZmVsc2UoYmxhbmtSb3cgPiA4MCwgVFJVRSwgRkFMU0UpCgptaXNzaW5nVGFiIDwtIHl0ICU+JQogIGZpbHRlcihtb3N0TWlzc2luZz09VCkgJT4lCiAgZHBseXI6OnNlbGVjdChkaXN0cmljdCwgZW51bWVyYXRvcl9pbl8xNmIsIHZpbGxhZ2UsIHNhbXBsZV9pZCwgbmFtZSkKa2FibGUobWlzc2luZ1RhYiwgZm9ybWF0PSdtYXJrZG93bicsIGNhcHRpb249Ik9icyB3aXRoIG92ZXIgODAgbWlzc2luZyB2YWx1ZXMiKQpgYGAKClNvbWUgb2JzZXJ2YXRpb25zIGhhdmUgYHIgYXMuY2hhcmFjdGVyKG5hUm93JFZhcjFbbnJvdyhuYVJvdyldKWAgb2Ygb2JzZXJ2YXRpb25zIG1pc3NpbmcuIFdoYXQncyBnb2luZyBvbiB3aXRoIHRoZXNlPyBJJ20gb25seSBzaG93aW5nIHJvd3Mgd2l0aCBncmVhdGVyIHRoYW4gMjUlIG1pc3NpbmcuIEl0J3Mgc29tZXdoYXQgYXJiaXRyYXJ5IGJ1dCB0byBub3QgaGF2ZSBkYXRhIGZvciBhIGZvdXJ0aCBvZiB0aGUgc3VydmV5IHNlZW1zIG9kZC4KCiMjIE1hdGNoZXMgd2l0aCBwcmV2aW91cyByb3VuZHMKCmBgYHtyfQojdGFibGUoeXQkc2FtcGxlX2lkICVpbiUgdW5pcXVlKGZpZWxkRGF0JHNhbXBsZV9pZCkpCmBgYAoKPiBUaHJvdWdoIGByIGZvcm1hdChTeXMudGltZSgpLCAnJUIgJWQsICVZJylgIHdlIGhhdmUgb25lIHNvaWwgc2FtcGxlIGlkIGluIHJvdW5kIDIgdGhhdCBkb2Vzbid0IGV4aXN0IGluIHByZXZpb3VzIHJvdW5kcy4gSXQgaXMgc2FtcGxlX2lkIGByIHl0JHNhbXBsZV9pZFsheXQkc2FtcGxlX2lkICVpbiUgdW5pcXVlKGZpZWxkRGF0JHNhbXBsZV9pZCldYC4KCldoYXQgaXMgdXAgd2l0aCB0aGF0IG9ic2VydmF0aW9uPwoKIyMgQ29tcGxldGlvbiByYXRlcwoKYGBge3J9CmJhc2VDb21wbGV0ZSA8LSBmaWVsZERhdCAlPiUKICBmaWx0ZXIoc2Vhc29uID09IjE1YiIpICU+JQogIGRwbHlyOjpzZWxlY3Qoc2FtcGxlX2lkKSAKCmNvbXBCIDwtIHJvdW5kKHByb3AudGFibGUodGFibGUoYmFzZUNvbXBsZXRlJHNhbXBsZV9pZCAlaW4lIHl0JHNhbXBsZV9pZCkpLDIpCgpyMUNvbXBsZXRlIDwtIGZpZWxkRGF0ICU+JQogIGZpbHRlcihzZWFzb24gPT0iMTZiIikgJT4lCiAgZHBseXI6OnNlbGVjdChzYW1wbGVfaWQpIAoKCmNvbXBSMSA8LSByb3VuZChwcm9wLnRhYmxlKHRhYmxlKHIxQ29tcGxldGUkc2FtcGxlX2lkICVpbiUgeXQkc2FtcGxlX2lkKSksMikKYGBgCgo+IFRocm91Z2ggYHIgZm9ybWF0KFN5cy50aW1lKCksICclQiAlZCwgJVknKWAgd2UndmUgZm91bmQgYHIgY29tcEJbWzJdXSoxMDBgJSBvZiBiYXNlbGluZSBmYXJtZXJzLiBXZSBoYXZlIGByIG5yb3coYmFzZUNvbXBsZXRlKS10YWJsZShiYXNlQ29tcGxldGUkc2FtcGxlX2lkICVpbiUgeXQkc2FtcGxlX2lkKVtbMl1dYCB0byBnby4KCj4gVGhyb3VnaCBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCICVkLCAlWScpYCB3ZSd2ZSBmb3VuZCBgciBjb21wUjFbWzJdXSoxMDBgJSBvZiByb3VuZCAxIGZhcm1lcnMuIFdlIGhhdmUgYHIgbnJvdyhyMUNvbXBsZXRlKS10YWJsZShyMUNvbXBsZXRlJHNhbXBsZV9pZCAlaW4lIHl0JHNhbXBsZV9pZClbWzJdXWAgdG8gZ28uCgpBcyB3ZSBnZXQgY2xvc2VyIHRvIHRoZSBlbmQgb2YgZW51bWVyYXRpb24gSSB3aWxsIHByb2R1Y2UgYSByZXBvcnQgb2Ygc2FtcGxlX2lkcyB0aGF0IGhhdmUgbm90IHlldCBiZWVuIHN1cnZleWVkIHNvIHdlIGNhbiB1bmRlcnN0YW5kIHByZWNpc2VseSB3aHkgc29tZSBmYXJtZXJzIHdlcmUgbm90IGZvdW5kIGFnYWluLgoKIyMgQXR0cml0aW9uIHN1bW1hcnkKCmBgYHtyfQojIGNvZGUgdG8gY2hlY2sgbWVyZ2UgbWF0Y2ggYmVmb3JlIG1hdGNoIGlzIHBlcmZvcm1lZAojIHRoZSBjb2RlIHNob3VsZCBzaG93IHlvdSBob3cgbWFueSBvdmVybGFwcyB5b3UgaGF2ZSBpbiB5b3VyIG1lcmdlIHZhcmlhYmxlCiMgYW5kIGEgc3VtbWFyeSBvZiB0aGUgdmFsdWVzIHRoYXQgZG9uJ3QgbWF0Y2gKCiMgdGVzdGVkIHVzaW5nIGtlX3JvdW5kXzFfcHkKCnZlY0ZpbGxlciA8LSBmdW5jdGlvbih2ZWMpewogIHZlY1syXSA9IGlmZWxzZShpcy5uYSh2ZWNbMl0pLCAwLCB2ZWNbMl0pCiAgcmV0dXJuKHZlYykKfQoKCm1lcmdlUmVwb3J0IDwtIGZ1bmN0aW9uKG1hc3RlciwgdXNpbmcpewogIAogICMgZGF0MSBpbnRvIGRhdDIKICAKICBjMSA8LSB2ZWNGaWxsZXIodGFibGUobWFzdGVyICVpbiUgdXNpbmcpKQogIGMyIDwtIHZlY0ZpbGxlcih0YWJsZSh1c2luZyAlaW4lIG1hc3RlcikpCiAgCiAgbm90TWF0Y2gxIDwtIG1hc3RlclshbWFzdGVyICVpbiUgdXNpbmddCiAgbm90TWF0Y2gyIDwtIHVzaW5nWyF1c2luZyAlaW4lIG1hc3Rlcl0KICAKICB0YWIgPC0gZGF0YS5mcmFtZShyYmluZChjMSwgYzIpKQogIHJvd25hbWVzKHRhYikgPC0gYygiTWFzdGVyIGluIFVzaW5nIiwgIlVzaW5nIGluIE1hc3RlciIpCiAgCiAgb3V0TGlzdCA8LSBsaXN0KHRhYiwgbm90TWF0Y2gxLCBub3RNYXRjaDIpCiAgbmFtZXMob3V0TGlzdCkgPC0gYygibWF0Y2hpbmcudGFibGUiLCAibWlzc2luZy5mcm9tLnVzaW5nIiwgIm1pc3NpbmcuZnJvbS5tYXN0ZXIiKQogIAogIHJldHVybigKICAgIG91dExpc3QKICApCiAgCiAgCn0KCmF0dFJlcG9ydCA8LSBtZXJnZVJlcG9ydChiYXNlQ29tcGxldGUkc2FtcGxlX2lkLCB5dCRzYW1wbGVfaWQpCmBgYAoKV2UgY3VycmVudGx5IGhhdmUgYHIgbGVuZ3RoKGF0dFJlcG9ydCRtaXNzaW5nLmZyb20udXNpbmcpYCBtb3JlIHN1cnZleXMgdG8gY29tcGxldGUgKmZyb20gdGhlIGJhc2VsaW5lKi4gVGhlIGNvbXBsZXRlIGxpc3Qgb2YgbWlzc2luZyBmYXJtZXIgaWRzIHdpbGwgYmUgc2hhcmVkIG9uY2Ugd2UncmUgZG93biB0byBhIG1vcmUgcmVhc29uYWJsZSBudW1iZXIuCgojIyMgQXR0cml0aW9uIGZhcm1lciBsaXN0CmBhdHRPdXRgIGlzIHRoZSBsaXN0IG9mIGJhc2VsaW5lIGZhcm1lcnMgbm90IGZvdW5kIGR1cmluZyB0aGUgc2Vjb25kIHN1cnZleSByb3VuZC4gYGF0dFJlcG9ydGAgYXJlIHRob3NlIGZhcm1lcnMgdGhhdCBhcmUgbWlzc2luZwoKYGBge3J9CmF0dE91dCA8LSBmaWVsZERhdCAlPiUKICBmaWx0ZXIoc2Vhc29uID09IjE1YiIpICU+JQogIGZpbHRlcihzYW1wbGVfaWQgJWluJSBhdHRSZXBvcnQkbWlzc2luZy5mcm9tLnVzaW5nKSAlPiUKICBkcGx5cjo6c2VsZWN0KHNhbXBsZV9pZCwgZGlzdHJpY3QsIHZpbGxhZ2UpCgoKI2xvYWQgdGhlIGJhc2VsaW5lIGRhdGEKbG9hZCgiLi4vcndfcm91bmRfMS9yYXdCYXNlbGluZVdpdGhJZGVudGlmZXJzLlJkYXRhIikKYXR0cml0aW9uVGFiIDwtIGQgJT4lIAogIGRwbHlyOjpzZWxlY3QoZGlzdHJpY3QsIHNlbGVjdGVkX2NlbGwsIHVtdWR1Z3VkdSwgIHNhbXBsZV9pZCwgZmFybWVyX25hbWUpICU+JQogIG11dGF0ZShzYW1wbGVfaWQgPSB0b2xvd2VyKHNhbXBsZV9pZCksICMgYmVjYXVzZSB3ZSdyZSBtYWtyaW5nIHRob3NlIG5vdCBmb3VuZAogICAgICAgICBmb3VuZCA9IGlmZWxzZShzYW1wbGVfaWQgJWluJSBhdHRPdXQkc2FtcGxlX2lkLCBGQUxTRSwgVFJVRSkpICU+JQogIGxlZnRfam9pbiguLCB5dHdvWywgYygieDE4YS5mYXJtZXIubmFtZSIsICJ4MThiLm5hbWUub2YudGhlLnJlc3BvbmRlbnQiLCAieDE5YS5mYXJtZXIucGhvbmUubnVtYmVyIiwgInguZm9ybS5zYW1wbGVfaWQiLAogICAgICAgICAgICAgICAgICAgICAgICAieDIwLmluLmNhc2Uud2UuY2FuLm5vdC5yZWFjaC50aGUuY2xpZW50LmRpcmVjdGx5Li5wbGVhc2UucHJvdmlkZS5hLm5laWdoYm9yLnMucGhvbmUubnVtYmVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgIngxNGEud2VyZS4ueW91LmEudHVidXJhLmNsaWVudC4xN2EuIiwgIngxNGIuYXJlLnlvdS5hLnR1YnVyYS5jbGllbnQuMTdiLiIsIngxNGMuYXJlLnlvdS5hLnR1YnVyYS5jbGllbnQuaW4uMThhLiIpXSwgYnk9Yygic2FtcGxlX2lkIj0gInguZm9ybS5zYW1wbGVfaWQiKSkKCmF0dHJpdGlvblRhYiA8LSBhdHRyaXRpb25UYWJbLGMoNCwxLDIsMyw1LDYsIDc6MTMpXQojbGVuZ3RoKGF0dHJpdGlvblRhYiRzYW1wbGVfaWQpPT1sZW5ndGgodW5pcXVlKGF0dHJpdGlvblRhYiRzYW1wbGVfaWQpKQoKCiMgbG9hZCBkYXRhIGZyb20gRXJpYyBKIG9uIDkvMTEgLSBjb21iaW5lIG15IG1pc3NpbmduIHdpdGggdGhvc2Ugd2l0aG91dCBhIHNhbXBsZSBhbmQgdXBkYXRlIHRoZSBnb29nbGVzaGVldAplakRhdDEgPC0gcmVhZF94bHN4KCJhdHRyaXRpb24gdGFibGUyMDE3IDA5IDExX0VKLnhsc3giLCBzaGVldD0xKSAlPiUgCiAgZHBseXI6OnNlbGVjdChzYW1wbGVfaWQsIGBzYW1wbGUgY29sbGVjdGVkIChmcm9tIHRyYWNrZXIpP2AsIGByZWFzb24gKGZyb20gdHJhY2tlcilgKSAlPiUKICByZW5hbWUoc2FtcGxlX2NvbGxlY3RlZCA9IGBzYW1wbGUgY29sbGVjdGVkIChmcm9tIHRyYWNrZXIpP2AsCiAgICAgICAgIHJlYXNvbiA9IGByZWFzb24gKGZyb20gdHJhY2tlcilgKQoKZWpEYXQyIDwtIHJlYWRfeGxzeCgiYXR0cml0aW9uIHRhYmxlMjAxNyAwOSAxMV9FSi54bHN4Iiwgc2hlZXQ9MikgJT4lIAogIGRwbHlyOjpzZWxlY3Qoc2FtcGxlX2lkLCBgc2FtcGxlIGNvbGxlY3RlZD9gLCByZWFzb24pICU+JQogIHJlbmFtZShzYW1wbGVfY29sbGVjdGVkID0gYHNhbXBsZSBjb2xsZWN0ZWQ/YCkgJT4lCiAgcmJpbmQoLiwgZWpEYXQxKQoKI2xlbmd0aChlakRhdDIkc2FtcGxlX2lkKT09bGVuZ3RoKHVuaXF1ZShlakRhdCRzYW1wbGVfaWQpKSAjIGR1cGxpY2F0ZXMgaW4gdGhlIG1pc3NpbmcgZGF0YQoKIyByZXBvcnQgbWlzc2luZyB2YWx1ZXMgaW4gdGhlIGR1cGxpY2F0ZXMKZHVwcyA8LSBlakRhdDJbZHVwbGljYXRlZChlakRhdDIkc2FtcGxlX2lkKSwgInNhbXBsZV9pZCJdICU+JSAKICBmaWx0ZXIoIWlzLm5hKHNhbXBsZV9pZCkpCgojIHNob3cgYWxsIHRoZSBmYXJtZXJzIGZvciB3aGljaCB3ZSBoYXZlIG11bHRpcGxlIHJlYXNvbnMgbGlzdGVkOgojIGVqRGF0MiAlPiUKIyAgIGZpbHRlcihlakRhdDIkc2FtcGxlX2lkICVpbiUgZHVwcyRzYW1wbGVfaWQpICU+JQojICAgYXJyYW5nZShzYW1wbGVfaWQpICU+JQojICAga2FibGUoLiwgZm9ybWF0PSdtYXJrZG93bicpCmBgYAoKKipFcmljKiosIHRoZXJlIGlzbid0IGNsYXJpdHkgaW4gSmVhbm5ldHRlJ3MgZm9ybSBhYm91dCB3aGF0IGhhcyBhbmQgaGFzIG5vdCBiZWVuIGNvbGxlY3RlZC4gQ2FuIHNoZSBtYWtlIGEgbWFzdGVyIGRhdGFiYXNlIGluc3RlYWQgb2YgdHdvIHNlcGFyYXRlIG9uZXM/IEFkZCBhIHNlY29uZCBjb2x1bW4gaWYgeW91IHdhbnQgdG8gaW5kaWNhdGUgdGhlIGlzc3VlLiBGb3IgdGhlIHRpbWUgYmVpbmcgSSdtIG5vdCBnb2luZyB0byBhZGQgdGhpcyBpbnRvIHRoZSBgcndSMkF0dHJpdGlvbmAgZ29vZ2xlIHNoZWV0IHVudGlsIHdlIGhhdmUgYSBkZWZpbml0aXZlIGFuc3dlciBvbiB3aGF0IHRoZSBzdGF0dXMgaXMuCgpgYGB7cn0KIyBub3cgcHV0IHRoaXMgaW5mb3JtYXRpb24gd2l0aCB0aGUgYXR0cml0aW9uIFRhYgojYXR0cml0aW9uVGFiIDwtIGxlZnRfam9pbihhdHRyaXRpb25UYWIsIGVqRGF0MiwgYnk9InNhbXBsZV9pZCIpCiAgCgp3cml0ZS5jc3YoYXR0cml0aW9uVGFiLCBmaWxlPXBhc3RlMCgiYXR0cml0aW9uVGFicy9hdHRyaXRpb24gdGFibGUiLCBmb3JtYXQoU3lzLnRpbWUoKSwgJyVZICVtICVkJyksICIuY3N2IiksIHJvdy5uYW1lcz1GKQoKCgojIGFsc28gdXBkYXRlIGEgZ29vZ2xlc2hlZXQgdG8gbWFrZSBjb2xsYWJvcmF0aW5nIG9uIHRoaXMgcG9zc2libGU6CmxpYnJhcnkoZ29vZ2xlc2hlZXRzKQoKIyBmaXJzdCB1cGxvYWRpbmcgb2YgdGhlIGRhdGEKIyB0ZXN0IDwtIGdzX3VwbG9hZChmaWxlPXBhc3RlMCgiYXR0cml0aW9uVGFicy9hdHRyaXRpb24gdGFibGUiLCBmb3JtYXQoU3lzLnRpbWUoKSwgJyVZICVtICVkJyksICIuY3N2IiksICJyd1IyQXR0cml0aW9uIiwgb3ZlcndyaXRlPVQpCgojIG5vdyBJIHdhbnQgdG8gb25seSBlZGl0IGNlcnRhaW4gcm93czoKIyB0ZXN0IDwtIHRlc3QgJT4lIAojICAgZ3NfZWRpdF9jZWxscyhpbnB1dCA9IGF0dHJpdGlvblRhYiRmb3VuZCwKIyAgICAgICAgICAgICAgICAgYW5jaG9yID0gIkYyIiwgYnlyb3c9RkFMU0UpCiMgCiMgIyBicmluZyBpbiBpbmZvIGZyb20gTSZFIHRlYW0sIG1lcmdlIHJlYXNvbnMgd2l0aCBjdXJyZW50IHRhYmxlIGFuZCBvbmx5IHNob3cgdGhlIGZhcm1lcnMgZm9yIHdoaWNoIHdlIGFyZSBzdGlsbCBtaXNzaW5nIGFuIGV4cGxhbmF0aW9uCiMgCiMgdGVzdCA8LSByZWFkX3hsc3goIkZhcm1lciBub3QgZmluZCBmb3IgU0hTIHN1cnZleSA3LjkuMjAxNy54bHN4Iiwgc2hlZXQ9MikgJT4lCiMgICByZW5hbWUoc2FtcGxlX2lkID0gYFNvaWwgSURgKSAlPiUKIyAgIG11dGF0ZShzYW1wbGVfaWQgPSB0b2xvd2VyKHNhbXBsZV9pZCkpCgojIHRhYmxlKHRlc3Qkc2FtcGxlX2lkICVpbiUgYXR0cml0aW9uVGFiJHNhbXBsZV9pZCkgIyBkbyB0aGV5IGFwcGVhciBhbW9uZyB0aGUgbWlzc2luZz8KIyB0YWJsZSh0ZXN0JHNhbXBsZV9pZCAlaW4lIHN1YnNldChmaWVsZERhdCwgZmllbGREYXQkc2Vhc29uPT0iMTViIikkc2FtcGxlX2lkKSAjIHRoZXkgYXJlIGZhcm1lcnMgYnV0IEkndmUgZm91bmQgdGhlbQoKICAjIGRwbHlyOjpzZWxlY3QoYFJlYXNvbiBub3QgZm91bmRgLCBgUmVhc29uIG5vdCBmb3VuZCBvdGhlcmAsIERpc3RyaWN0LCBDZWxsLCBWaWxsYWdlLCBgQ2VsbCBmaWVsZGAsIGBSZXNwb25kZW50IG5hbWVgLCBgRmFybWVyIHRlbGAsIGBSZXNwb25kZW50IHRlbGAsIGBOZWlnaGJvciB0ZWxgLCBzYW1wbGVfaWQpICU+JQogICMgbGVmdF9qb2luKC4sIGF0dHJpdGlvblRhYiwgYnk9InNhbXBsZV9pZCIpICU+JQogICMgYXMuZGF0YS5mcmFtZSgpCgoKCgojIGZpbmQgdGhlIGZhcm1lciBuYW1lIGluIHRoZSBvcmlnaW5hbCBiYXNlbGluZSBkYXRhPwoKZGF0YXRhYmxlKGF0dHJpdGlvblRhYikKYGBgCgojIERhdGEgcmVhbGl0eSBjaGVjawoKVGhlIHZhcmlhYmxlIG5hbWVzIGFyZSBub3QgZ3JlYXQuIEkgdGhpbmsgaXQncyBkdWUgdG8gdGhlIENvbW1DYXJlIEFQSSBleHBvcnQuIEknbSBnb2luZyB0byBzZWUgaWYgdGhlcmUncyBhbiBlYXNpZXIgd2F5IHRvIGhhdmUgdWVzYWJsZSB2YXJpYWJsZSBuYW1lcy4gSSd2ZSBjcmVhZXRkIGEgQ0MgZXhwb3J0IHRpdGxlZCAiTSZFIC0gU29pbCBIZWFsdGggU3R1ZHkgLSAxN0IgVWJ1dGFrYSAoU29pbCkiIG9uIEF1Z3VzdCA4dGguIEknbSBvbmx5IHVzaW5nIGl0IHRvIGdldCBtb3JlIHVzYWJsZSB2YXJpYWJsZSBuYW1lcyBxdWlja2x5LiBJZGVhbGx5IHRoZXJlJ2QgYmUgYXdheSB0byBnZXQgdGhhdCBpbmZvIGRpcmVjdGx5IGZyb20gQ29tbUNhcmUuCgpgYGB7cn0KdmFyTmFtZXMgPC0gcmVhZF9jc3YoIk0mRSAtIFNvaWwgSGVhbHRoIFN0dWR5IC0gMTdCIFVidXRha2EgKFNvaWwpICgyMDE3LTA4LTA0KSAyMDE3LTA4LTA0LmNzdiIpICU+JSAKICBzZXROYW1lcyhnc3ViKCJmb3JtLiIsICIiLCBuYW1lcyguKSkpICU+JQogIHNldE5hbWVzKGdzdWIoImZhcm1lci4iLCAiIiwgbmFtZXMoLikpKSAlPiUKICBzZXROYW1lcyhnc3ViKCJwcmltXzE3YV8uIiwgIiIsIG5hbWVzKC4pKSkgJT4lCiAgc2V0TmFtZXMoZ3N1Yigic2VjXzE3YV8uIiwgIiIsIG5hbWVzKC4pKSkgJT4lCiAgc2V0TmFtZXMoZ3N1YigicHJpbV8xN2JfLiIsICIiLCBuYW1lcyguKSkpICU+JQogIHNldE5hbWVzKGdzdWIoInNlY18xN2JfLiIsICIiLCBuYW1lcyguKSkpICU+JQogIHNldE5hbWVzKGdzdWIoImFtbWVuZF8xN2FfLiIsICIiLCBuYW1lcyguKSkpICU+JQogIHNldE5hbWVzKGdzdWIoImFtbWVuZF8xN2JfLiIsICIiLCBuYW1lcyguKSkpICU+JSAKICBhcy5kYXRhLmZyYW1lKCkKCgpuYW1lcyh5dClbMTE6MTEyXSA8LSBuYW1lcyh2YXJOYW1lcylbMzoxMDRdCiMgcmVuYW1lIG9uZSB2YXJpYWJsZSB0byByZW1vdmUgZHVwbGljYXRlcwpuYW1lcyh5dClbMzFdIDwtICJuYW1lT25lIgpuYW1lcyh5dCkgPC0gdG9sb3dlcihuYW1lcyh5dCkpCiMgbWFudWFsbHkgZml4IGEgY291cGxlIG90aGVyIG5hbWVzCm5hbWVzKHl0KVs1M10gPC0gImNyb3AxX3lpZWxkX2NvbXBhcmlzb25fMTdhIgpuYW1lcyh5dClbNThdIDwtICJjcm9wMl95aWVsZF9jb21wYXJpc29uXzE3YSIKCmBgYAoKIyMgQ2F0ZWdvcmljYWwgdmFyaWFibGVzCgpgYGB7cn0KY2F0VmFycyA8LSBuYW1lcyh5dClbc2FwcGx5KHl0LCBmdW5jdGlvbih4KXsKICBpcy5jaGFyYWN0ZXIoeCkKfSldCgplbnVtQ2xlYW4gPC0gZnVuY3Rpb24oZGF0LCB4LCB0b1JlbW92ZSl7CiAgZGF0Wyx4XSA8LSBpZmVsc2UoZGF0Wyx4XSAlaW4lIHRvUmVtb3ZlLCBOQSwgZGF0Wyx4XSkKICByZXR1cm4oZGF0Wyx4XSkKfQoKc3RyVGFibGUgPC0gZnVuY3Rpb24oZGF0LCB4KXsKICB2YXJOYW1lID0geAogIHRhYiA9IGFzLmRhdGEuZnJhbWUodGFibGUoZGF0Wyx4XSwgdXNlTkEgPSAnaWZhbnknKSkKICB0YWIgPSB0YWJbb3JkZXIodGFiJEZyZXEsIGRlY3JlYXNpbmcgPSBUKSxdCiAgZW5kID0gaWZlbHNlKGxlbmd0aCh0YWIkVmFyMSk8MTAsIGxlbmd0aCh0YWIkVmFyMSksIDEwKQogIHJlcE9yZGVyID0gcGFzdGUodGFiJFZhcjFbMTplbmRdLCBjb2xsYXBzZT0iLCAiKQogIG91dCA9IGRhdGEuZnJhbWUodmFyaWFibGUgPSB2YXJOYW1lLAogICAgICAgICAgICAgICAgICAgcmVzcG9uc2VzID0gcmVwT3JkZXIpCiAgCiAgcmV0dXJuKG91dCkKfQoKIyBjbGVhbiB1cCBrbm93biB2YWx1ZXMKY2F0RW51bVZhbHMgPC0gYygiLTk5IiwgIi04OCIsICItIDk5IiwgIi05OS4wIiwgIjg4IiwgIl84OCIsICItIDg4IiwgIjAuODgiLAogICAgICAgICAgICAgICAgICItLTg4IiwgIl9fODgiLCAiLTg4LjAiLCAiOTkuMCIpCnl0WyxjYXRWYXJzXSA8LSBzYXBwbHkoY2F0VmFycywgZnVuY3Rpb24oeSl7CiAgeXRbLHldIDwtIGVudW1DbGVhbih5dCx5LCBjYXRFbnVtVmFscykKfSkKCiMgcHV0IGFsbCBjYXRlZ29yaWNhbCB2YWx1ZXMgaW4gbG93ZXIKeXRbLGNhdFZhcnNdIDwtIHNhcHBseSh5dFssY2F0VmFyc10sIGZ1bmN0aW9uKHgpIHRvbG93ZXIoeCkpCgpyZXNwb25zZVRhYmxlIDwtIGRvLmNhbGwocmJpbmQsIGxhcHBseShjYXRWYXJzLCBmdW5jdGlvbih4KXsKICBzdHJUYWJsZSh5dCwgeCkKfSkpCmBgYAoKIyMjIFRhYmxlIG9mIGNhdGVnb3JpY2FsIHJlc3BvbnNlcwoKYGBge3J9CmthYmxlKHJlc3BvbnNlVGFibGUsIGZvcm1hdD0ibWFya2Rvd24iKQpgYGAKCiMjIyBDYXRlZ29yaWNhbCB2YXIgZ3JhcGhzCgoqIGRpc3RyaWN0XzE3YiBuYW1lcyBhcmUgc3BlbGxlZCB3cm9uZy4gSG93IGlzIHRoYXQgcG9zc2libGU/IERvIHdlIGNhcmU/CgpgYGB7cn0KcmVwR3JhcGhzIDwtIGZ1bmN0aW9uKGRhdCwgeCl7CiAgdGFiID0gYXMuZGF0YS5mcmFtZSh0YWJsZShkYXRbLHhdLCB1c2VOQSA9ICdpZmFueScpKQogIHRhYiA9IHRhYltvcmRlcih0YWIkRnJlcSwgZGVjcmVhc2luZyA9IFQpLF0KICBwcmludCgKICAgIGdncGxvdChkYXRhPXRhYiwgYWVzKHg9VmFyMSwgeT1GcmVxKSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsKICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICAgICAgbGFicyh0aXRsZSA9cGFzdGUwKCJDb21wb3NpdGlvbiBvZiB2YXJpYWJsZTogIiwgeCkpCiAgKQp9CgphZG1pblZhcnMgPC0gdG9sb3dlcihjKG5hbWVzKHl0KVtncmVwKCJtZXRhIiwgbmFtZXMoeXQpKV0sImVudW1fbmFtZSIsICJ0ZXh0X2ZpbmFsLnBob3RvIiwgICJwYXJ0aWNpcGF0aW9uIiwgInJlZnVzYWwiLCAicGhvbmUiLCAgImNvbW1lbnQiLCAiZ3BzIiwgInNhbXBsZV9pZCIsICJzYW1wbGluZy5iYXJjb2RlIiwgImlkIiwgImRvbWFpbiIsICJkYXRlX2hlYWRlciIsICJmb3JtLmNhc2UuLmNhc2VfaWQiLCAic2l0ZSIsICJkaXN0cmljdDEiLCAic2l0ZTEiLCAicGxvdC5sb2NhdGlvbiIsICJOZXdfc29pbF9zYW1wbGVfaWQiLCAiI2Zvcm0vU2FtcGxpbmcyMDE3X0NvbXBsZXRlIiwgImFwcGZvcm1pZCIsbmFtZXMoeXQpW2dyZXAoInNvaWxfaWQiLCBuYW1lcyh5dCkpXSwgIm5hbWVPbmUiLCAidGVsIiwgInRlbF9yZXNwb25kZW50IiwgIm5laWdoYm9yX3RlbCIsICJmaW5pc2hfdGltZSIsICJvdGhlcl9jb21tZW50cyIsICJEZXNjcmlwdGlvbiIsICJuZWlnaGJvcl9vcl92b2lzaW5fcGhvbmUiLCAibmFtZSIsICJjZWxsX2ZpZWxkXzE3YiIsICJuYW1lX3Jlc3BvbmRlbnQiLCJyZXNwb25kZW50X2luXzE2YiIsImdwc19oaWRkZW4iLCAiZmFybWVyX3Bob25lIiwgInJlc3BvbmRlbnRfcGhvbmUiLCAidmlsbGFnZSIsICJjZWxsIiwgbmFtZXMoeXQpW2dyZXAoImVudW1lcmF0b3IiLCBuYW1lcyh5dCkpXSwgInN0YXJ0X3RpbWUiLCAidmlsbGFnZV8xN2IiLCAiY2VsbF9pbnB1dF8xN2IiLCAibm90X2ZpbmRfd2h5X290aGVyIiwgImNvbXBvc3Rfb3RoZXJfMTdhIikpCm5vbkFkbWluVmFycyA8LSBjYXRWYXJzWyFjYXRWYXJzICVpbiUgYWRtaW5WYXJzXQoKZm9yKGkgaW4gMTpsZW5ndGgobm9uQWRtaW5WYXJzKSl7CiAgcmVwR3JhcGhzKHl0LCBub25BZG1pblZhcnNbaV0pCn0KYGBgCiMjIE51bWVyaWMgdmFyaWFibGVzCgpgYGB7cn0KbnVtVmFycyA8LSBuYW1lcyh5dClbc2FwcGx5KHl0LCBmdW5jdGlvbih4KXsKICBpcy5udW1lcmljKHgpCn0pXQpgYGAKCkJhc2ljIGNsZWFuaW5nIG9mIGtub3duIGlzc3VlcyBsaWtlIGVudW1lcmF0b3IgY29kZXMgZm9yIERLLCBOV1IsIGV0Yy4KYGBge3J9CmVudW1WYWxzIDwtIGMoLTg4LC04NSwgLTk5LCAtOSkKCnl0WyxudW1WYXJzXSA8LSBzYXBwbHkobnVtVmFycywgZnVuY3Rpb24oeSl7CiAgeXRbLHldIDwtIGVudW1DbGVhbih5dCx5LCBlbnVtVmFscykKICB5dFsseV0gPC0gYXMubnVtZXJpYyh5dFsseV0pCn0pCmBgYAoKIyMjIE51bWVyaWMgdmFyIGdyYXBocwoKYGBge3J9CnRlbXAgPC0gbnVtVmFycwoKCm5vTmVlZCA8LSBjKCJpbnRyby5pbnRybyIsICJ0ZXh0X2ZpbmFsLmRfcGhvdG8iLCAidGV4dF9maW5hbC5kX3NvaWxzYW1wbGUiKQpudW1WYXJzIDwtIG51bVZhcnNbIW51bVZhcnMgJWluJSBub05lZWRdCiMgcmVtb3ZlIHZhcmlhYmxlcyB0aGF0IGFyZSBlbnRpcmVseSBtaXNzaW5nCnRvdGFsbHlNaXNzaW5nIDwtIHNhcHBseSh5dFssbnVtVmFyc10sIGZ1bmN0aW9uKHgpewogIGFsbChpcy5uYSh4KSkKICB9KQoKbnVtVmFycyA8LSBudW1WYXJzW3RvdGFsbHlNaXNzaW5nPT1GXQoKCmZvcihpIGluIDE6bGVuZ3RoKG51bVZhcnMpKXsKICAgIGlmKGxlbmd0aCh1bmlxdWUoeXRbLG51bVZhcnNbaV1dKSk+MTApewogICAgICBwcmludChnZ3Bsb3QoZGF0YT15dCwgYWVzKHg9eXRbLG51bVZhcnNbaV1dKSkgKyAgCiAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KCkgKyAKICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKyAKICAgICAgICAgICAgICBsYWJzKHggPSBudW1WYXJzW2ldKQogICAgICAgICAgICApCiAgICB9IGVsc2V7CiAgICBwcmludChnZ3Bsb3QoZGF0YT15dCwgYWVzKHg9eXRbLG51bVZhcnNbaV1dKSkgKyAKICAgICAgICAgICAgZ2VvbV9oaXN0b2dyYW0oc3RhdD0iY291bnQiKSArIAogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKwogICAgICAgICAgICBsYWJzKHggPSBudW1WYXJzW2ldKQogICAgICApCiAgICB9CiAgICAjbXVsdGlwbG90KHRlbXAxLCB0ZW1wMiwgY29scyA9IDIKfQpgYGAKCiMgRm9sbG93IHVwCgpgYGB7ciBtZXNzYWdlPUZ9CmRldGVjdE91dGxpZXIgPC0gZnVuY3Rpb24oZGF0LCB4KXsKCiMgZnVuY3Rpb24gY2hlY2tzIGRpc3RyaWJ1dGlvbiBhbmQgaWYgbG9nbm9ybWFsLCBjb3ZlcnRzIGFuZCBvdXRwdXRzCiMgb3V0bGllcnMgZnJvbSBsb2cgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gaGF2ZSB0byByZW1vdmUgMHMgdG8gY2hlY2sKICBmaXRzIDwtIGxpc3QoCiBubyA9IGZpdGRpc3RyKGRhdFsseF1bY29tcGxldGUuY2FzZXMoZGF0Wyx4XSldLCJub3JtYWwiKSwKIGxvID0gZml0ZGlzdHIoKGRhdFsseF0pW2NvbXBsZXRlLmNhc2VzKGRhdFsseF0pICYgZGF0Wyx4XSE9MCAmIGRhdFsseF0+MF0sImxvZy1ub3JtYWwiKQogI2NhID0gZml0ZGlzdHIoZGF0Wyx4XVtjb21wbGV0ZS5jYXNlcyhkYXRbLHhdKV0sImNhdWNoeSIpLAogI3dlID0gZml0ZGlzdHIoZGF0Wyx4XVtjb21wbGV0ZS5jYXNlcyhkYXRbLHhdKV0sICJ3ZWlidWxsIikKICkKIyBnZXQgdGhlIGxvZ2xpa3MgZm9yIGVhY2ggbW9kZWwuLi4KZml0Q2hlY2sgPC0gc2FwcGx5KGZpdHMsIGZ1bmN0aW9uKGkpIGkkbG9nbGlrKQpiZXN0Rml0IDwtbmFtZXMod2hpY2gubWF4KGZpdENoZWNrKSkKCnRyYW5zIDwtIHNhcHBseShkYXRbLHhdLCBmdW5jdGlvbih5KXsKICBpZmVsc2UoYmVzdEZpdD09ImxvIiwgbG9nMTAoeSsxKSwgeSkKfSkKICAKICAKICBxMSA9IHN1bW1hcnkodHJhbnMpW1syXV0KICBxMyA9IHN1bW1hcnkodHJhbnMpW1s1XV0gCiAgaXFyID0gcTMtcTEKICBtYXJrICA9IGlmZWxzZSh0cmFucyA8IChxMSAtICgxLjUqaXFyKSkgfCB0cmFucyA+IChxMyArICgxLjUqaXFyKSksIDEsMCkKICAjIHRhYiA9IHJiaW5kKAogICMgICBzdW1tYXJ5KGRbLHhdKSwKICAjICAgc3VtbWFyeShkW21hcms9PTAsIHhdKQogICMgKQogIG91dCA9IGRhdFttYXJrPT0xLCBjKCJkaXN0cmljdCIsICJjZWxsIiwgImVudW1lcmF0b3IiLCAic2FtcGxlX2lkIiwgImZhcm1lcl9waG9uZSIsIHgpXQogIG91dCA9IG1lbHQob3V0LCBtZWFzdXJlLnZhcnMgPSB4KQogIG91dCA9IG91dFshaXMubmEob3V0JGRpc3RyaWN0KSxdCiAgCiAgcmV0dXJuKG91dCkKCn0KCnByaW50SVFSIDwtIGRvLmNhbGwocmJpbmQsIGxhcHBseShudW1WYXJzLCBmdW5jdGlvbih5KXsKICAjcHJpbnQoeSkKICByZXR1cm4oZGV0ZWN0T3V0bGllcih5dCwgeSkpCn0pKQoKcHJpbnRJUVIgPC0gcHJpbnRJUVJbb3JkZXIocHJpbnRJUVIkZW51bWVyYXRvcixwcmludElRUiRjZWxsLCBwcmludElRUiRzYW1wbGVfaWQpLF0KYGBgCgojIyBTcGVjaWZpYyBwb2ludHMKCkNvbXBvc3QgYXBwbGljYXRpb24gYW5kIHF1YW50aXR5CgpUaGlzIGFwcGVhcnMgdG8gYmUgb2RkZWQgY29kZWQuIFNvbWUgIkkgZGlkbid0IHVzZSBjb21wb3N0IiBhcmUgMHMgd2hpbGUgb3RoZXJzIGFyZSBOQS4gCmBgYHtyfQp0YWJsZSh5dCRrZ19jb21wb3N0XzE3YSwgeXQkY29tcG9zdF8xN2EsIHVzZU5BID0gJ2lmYW55JylbYygxOjEwKSxdCmBgYAoKYGBge3J9Cm1vZGlmeU91dGxpZXJPdXRwdXQgPC0gZnVuY3Rpb24oZGF0LCB2YXJuYW1lLCB2YWxzKXsKICBkYXQgPSBkcGx5cjo6ZmlsdGVyKGRhdCwgdmFyaWFibGUhPXZhcm5hbWUgJiAoIXZhbHVlICVpbiUgdmFscykpCiAgcmV0dXJuKGRhdCkKfQoKcHJpbnRJUVIgPC0gbW9kaWZ5T3V0bGllck91dHB1dChwcmludElRUiwgImZvdW5kIiwgMSkKcHJpbnRJUVIgPC0gbW9kaWZ5T3V0bGllck91dHB1dChwcmludElRUiwgImNvbXBvc3QiLCAxKQpwcmludElRUiA8LSBtb2RpZnlPdXRsaWVyT3V0cHV0KHByaW50SVFSLCAiY29tcG9zdF8xN2EiLCAwKQpwcmludElRUiA8LSBtb2RpZnlPdXRsaWVyT3V0cHV0KHByaW50SVFSLCAibl9jaGlja2VucyIsIDI6NykKCgpgYGAKCioqUmVhZCB0aGUgdmFsdWVzIGluIHRoaXMgdGFibGUgd2l0aCB0aGUgYWJvdmUgaGlzdG9ncmFtcyBhbmQgZGVuc2l0eSBwbG90cyBpbiBtaW5kLiBOb3QgYWxsIHRoZSB2YWx1ZXMgbGlzdGVkIGluIHRoZSB0YWJsZSB3aWxsIGJlIGltcG9zc2libGUgdmFsdWVzIGJ1dCB0aGV5IHdlcmUgZmxhZ2dlZCBmb3IgYmVpbmcgZmFyIGZyb20gdGhlIGNlbnRyYWwgbWFzcyBvZiB2YWx1ZXMgd2UgaGF2ZSBvbiB0aGF0IGRhdGEgcG9pbnQqKgoKYGBge3J9CmRhdGF0YWJsZShwcmludElRUikKYGBgCgpgYGB7cn0Kd3JpdGUuY3N2KHByaW50SVFSLCBmaWxlPXBhc3RlMCgib3V0cHV0LyIsICJyd19zaHNfcjIgdmFycyB0byBjaGVjayB1cGRhdGUiLGZvcm1hdChTeXMudGltZSgpLCAnJUIgJWQgJVknKSwgICIuY3N2IiksIHJvdy5uYW1lcyA9IEYpCgpmb3IoaSBpbiAxOmxlbmd0aCh1bmlxdWUocHJpbnRJUVIkZW51bWVyYXRvcikpKXsKICBvdXRTaGVldCA8LSBwcmludElRUltwcmludElRUiRlbnVtZXJhdG9yPT11bmlxdWUocHJpbnRJUVIkZW51bWVyYXRvcilbaV0sIF0KICB3cml0ZS5jc3Yob3V0U2hlZXQsIGZpbGU9cGFzdGUoIm91dHB1dCIsCiAgICAgICAgICBwYXN0ZSgicndfc2hzX3IyIHZhcnMgdG8gY2hlY2sgIiwgdW5pcXVlKHByaW50SVFSJGVudW1lcmF0b3IpW2ldLCAiLmNzdiIsIHNlcCA9ICIiKSwgc2VwID0gIi8iKSkKICAKfQpgYGAK